#ifndef _RINGBUFFER_H
#define _RINGBUFFER_H

#include <iostream>

#include "Log.h"

#ifdef _DEBUG

#include <assert.h>
#define ASSERT(x) assert(x)

#else

#define ASSERT(x)

#endif

template <typename T, typename INDEX, int SIZE>
struct RingBuffer
{
	RingBuffer()
	{
		//Set the start and end to the 0th element
		start = end = 0;
	}

	void Push(T type, INDEX index)
	{
		//Check that the index provided is greater than or equal to the last provided index
		if( index < bufferIndex[end] )
		{
			Log("Attempt to place a back in time element inside a RingBuffer, element rejected");
			return;
		}

		if( IsFull() )
		{
			//Buffer full, move the start up
			PopStart();
		}

		//Check if the end has reached one side of the ring
		if( (end + 1) < SIZE )
		{
			end += 1;
			buffer[end] = type;
			bufferIndex[end] = index;
			return;
		}

		//Reached end of ring, go back to start
		end = 0;
		buffer[0] = type;
		bufferIndex[end] = index;
	}
	T *Get(INDEX index)
	{
		//Return the data at the specified index or the next lowest
		if(start != end)
		{
			int currentPos = start;
			while( currentPos != end )
			{
				if( bufferIndex[currentPos] >= index )
				{
					//std::cout << bufferIndex[currentPos];
					return &buffer[currentPos];
				}

				//Increment position
				++currentPos;
				if(currentPos >= SIZE)
				{
					currentPos = 0;
				}
			}

			//Unable to find a valid index, return the end
			return &buffer[end];
		}

		return NULL;
	}

	void PopStart()
	{
		if( IsEmpty() )
		{
			return;
		}

		if( start == (SIZE - 1) )
		{
			start = 0;
			return;
		}

		++start;
	}
	void PopEnd()
	{
		if( IsEmpty() )
		{
			return;
		}

		if( end == 0 )
		{
			end = (SIZE - 1);
			return;
		}

		--end;
	}

	bool IsEmpty()
	{
		if(start == end)
		{
			return true;
		}
		return false;
	}
	bool IsFull()
	{
		//Full check when end is behind start
		if( end == (start - 1) )
		{
			return true;
		}

		//Single case full check when end is at SIZE and start is at 0
		if( start == 0 && end == (SIZE - 1) )
		{
			return true;
		}

		return false;
	}

	T buffer[SIZE];
	INDEX bufferIndex[SIZE];
	int start;
	int end;
};

#endif